﻿#region Copyright (c) 2012-10, Olaf Kober <amarok.projects@gmail.com>
//================================================================================
//	Permission is hereby granted, free of charge, to any person obtaining a copy
//	of this software and associated documentation files (the "Software"), to deal
//	in the Software without restriction, including without limitation the rights
//	to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
//	copies of the Software, and to permit persons to whom the Software is
//	furnished to do so, subject to the following conditions:
//
//	The above copyright notice and this permission notice shall be included in
//	all copies or substantial portions of the Software.
//
//	THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
//	IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
//	FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
//	AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
//	LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
//	OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
//	THE SOFTWARE.
//================================================================================
#endregion

using System;
using System.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;


namespace Amarok
{
	/// <summary>
	/// This type provides static methods that wrap task-related methods available on either Task, when 
	/// using .NET 4.5, or available on TaskEx, when using .NET 4 with Async Targeting Pack installed.
	/// </summary>
	public static class TaskHelper
	{
		#region Canceled

		// static data
		private static readonly Task sCanceledTask = _CreateCanceledTask();


		/// <summary>
		/// Gets a pre-instantiated and cached Task that is already canceled.
		/// </summary>
		public static Task Canceled
		{
			get
			{
				return sCanceledTask;
			}
		}


		private static Task _CreateCanceledTask()
		{
			var taskCompletionSource = new TaskCompletionSource<Object>();
			taskCompletionSource.SetCanceled();
			return taskCompletionSource.Task;
		}

		#endregion

		#region Completed

		// static data
		private static readonly Task sCompletedTask = _CreateCompletedTask();


		/// <summary>
		/// Gets a pre-instantiated and cached Task that is already completed.
		/// </summary>
		public static Task Completed
		{
			get
			{
				return sCompletedTask;
			}
		}


		private static Task _CreateCompletedTask()
		{
			var taskCompletionSource = new TaskCompletionSource<Object>();
			taskCompletionSource.SetResult(null);
			return taskCompletionSource.Task;
		}

		#endregion

		#region WhenAll

		/// <summary>
		/// Creates a task that will complete when all of the supplied tasks have completed.
		/// </summary>
		/// 
		/// <param name="tasks">
		/// The tasks to wait on for completion.</param>
		/// 
		/// <returns>
		/// A task that represents the completion of all of the supplied tasks.</returns>
		/// 
		/// <exception cref="ArgumentNullException">
		/// The tasks argument was null.</exception>
		/// <exception cref="ArgumentException">
		/// The tasks collection contained a null task.</exception>
		public static Task WhenAll(IEnumerable<Task> tasks)
		{
#if NET45
			return Task.WhenAll(tasks);
#else
			return TaskEx.WhenAll(tasks);
#endif
		}

		/// <summary>
		/// Creates a task that will complete when all of the supplied tasks have completed.
		/// </summary>
		/// 
		/// <param name="tasks">
		/// The tasks to wait on for completion.</param>
		/// 
		/// <returns>
		/// A task that represents the completion of all of the supplied tasks.</returns>
		/// 
		/// <exception cref="ArgumentNullException">
		/// The tasks argument was null.</exception>
		/// <exception cref="ArgumentException">
		/// The tasks collection contained a null task.</exception>
		public static Task WhenAll(params Task[] tasks)
		{
#if NET45
			return Task.WhenAll(tasks);
#else
			return TaskEx.WhenAll(tasks);
#endif
		}

		#endregion

		#region Run

		/// <summary>
		/// Queues the specified work to run on the ThreadPool and returns a Task handle for that work.
		/// </summary>
		/// 
		/// <param name="action">
		/// The work to execute asynchronously.</param>
		/// 
		/// <returns>
		/// A Task that represents the work queued to execute in the ThreadPool.</returns>
		/// 
		/// <exception cref="ArgumentNullException">
		///  The action parameter was null.</exception>
		public static Task Run(Action action)
		{
#if NET45
			return Task.Run(action);
#else
			return TaskEx.Run(action);
#endif
		}

		#endregion

		#region FromResult<T>

		/// <summary>
		/// Creates a <see cref="Task{TResult}"/> that is completed successfully with the specified result.
		/// </summary>
		/// 
		/// <typeparam name="T">
		/// The type of the result returned by the task.</typeparam>
		/// 
		/// <param name="result">
		/// The result to store into the completed task.</param>
		/// 
		/// <returns>
		/// The successfully completed task.</returns>
		public static Task<T> FromResult<T>(T result)
		{
#if NET45
			return Task.FromResult<T>(result);
#else
			var taskSource = new TaskCompletionSource<T>();
			taskSource.SetResult(result);
			return taskSource.Task;
#endif
		}

		#endregion

		#region Delay

		/// <summary>
		/// Starts a Task that will complete after the specified due time.
		/// </summary>
		/// 
		/// <param name="millisecondsDelay">
		/// The delay in milliseconds before the returned task completes.</param>
		/// <param name="cancellationToken">
		/// A CancellationToken that may be used to cancel the task before the due time occurs.</param>
		/// 
		/// <returns>
		/// The timed Task.
		/// </returns>
		/// 
		/// <exception cref="ArgumentOutOfRangeException">
		/// The dueTime argument must be non-negative or -1 and less than or equal to Int32.MaxValue.</exception>
		public static Task Delay(Int32 millisecondsDelay, CancellationToken cancellationToken)
		{
#if NET45
			return Task.Delay(millisecondsDelay, cancellationToken);
#else
			return TaskEx.Delay(millisecondsDelay, cancellationToken);
#endif
		}

		#endregion

	}
}
